﻿using ArtMath.Attribute;
using ArtMath.Component.Interface;
using ArtMath.Component.Line;
using ArtMath.Component.Point;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using ArtMath.CommonType;

namespace ArtMath.Component.Polygon
{
    /// <summary>
    /// 正多边形
    /// </summary>
    [Serializable]
    public class RegularPolygon : PolygonBase, ICenter
    {
        double bxj, r, nj, zxj;
        PointD[] tempLocation;
        PropertyDisplayer ctDisplayer;
        public RegularPolygon(SketchPad pad, string name, int linesCount, bool addToList = true) : base(pad, name, ToolTypeName.zdbx, addToList)
        {
            for (int i = 0; i < linesCount; i++)
            {
                Lines.Add(null);
            }
            tempLocation = new PointD[linesCount];
            InPoints = new PointBase[linesCount + 1];
            nj = (linesCount - 2) * 180.0 / linesCount * Core.Helper.Angle.DToR;
            zxj = Math.PI - nj;
            CenterDisplayer = new PropertyDisplayer(this, "Center");
        }
        [MultilingualCategory("Structure")]
        public override int LinesCount
        {
            get
            {
                return base.LinesCount;
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("Center")]
        public PointBase CenterPoint
        {
            get { return InPoints[InPoints.Length - 1]; }
            set { SetPoint(InPoints.Length - 1, value); }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("EdgeCenterDistance")]
        public double EdgeCenterDistance
        {
            get { return bxj; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("Radius")]
        public double Radius
        {
            get { return r; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("InteriorAngle"), TypeConverter(typeof(IntelliAngleConverter))]
        public double InteriorAngle
        {
            get { return nj; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("RPCentralAngle"), TypeConverter(typeof(IntelliAngleConverter))]
        public double CentralAngle
        {
            get { return zxj; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "Center", "Displayer")]
        public PropertyDisplayer CenterDisplayer
        {
            get { return ctDisplayer; }
            set { ctDisplayer = value; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("Center"), TypeConverter(typeof(IntelliPointConverter))]
        public PointD Center
        {
            get { return CenterPoint.ToPointD(); }
        }
        [Browsable(false)]
        public PointD PCenter
        {
            get { return CenterPoint.Pxy; }
        }
        [Browsable(false)]
        public PointD NewCenter
        {
            get { return CenterPoint.NewXY; }
        }
        [Browsable(false)]
        public PointD NewPCenter
        {
            get { return CenterPoint.NewPxy; }
        }
        public override int ClickTimes
        {
            get
            {
                return 2;
            }
        }
        public override PointCollectionBase[] GetInPointMovingRange(PointBase movePoint, Base sender = null)
        {
            int movcnt = CountMovablePoints();
            if (movcnt < InPoints.Length - 1)
            {
                throw new PointMovingException(this, Resources.Translate("SpecialRPCannotMove"));
            }
            return base.GetInPointMovingRange(movePoint, sender);
        }
        //public override bool Visible
        //{
        //    get
        //    {
        //        return base.Visible;
        //    }

        //    set
        //    {
        //        base.Visible = value;
        //        if (Center != null) Center.Visible = Visible;
        //    }
        //}
        //public override bool Selected_
        //{
        //    get
        //    {
        //        return base.Selected_;
        //    }

        //    set
        //    {
        //        base.Selected_ = value;
        //        if (Center != null)
        //        {
        //            Center.Selected_ = Selected_;
        //        }
        //    }
        //}
        //public override StyleState StyleState_
        //{
        //    get
        //    {
        //        return base.StyleState_;
        //    }

        //    set
        //    {
        //        base.StyleState_ = value;
        //        if (Center != null)
        //        {
        //            Center.StyleState_ = StyleState_;
        //        }
        //    }
        //}
        public override void RefreshPropertyDisplayersLocation()
        {
            CenterDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void RefreshPropertyDisplayersText()
        {
            CenterDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                CenterDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        public override void InChildrenIterator(Predicate<ShapeBase> act)
        {
            if (act == null) return;
            if (CenterPoint != null)
            {
                if (!act(CenterPoint)) return;
            }
            base.InChildrenIterator(act);
        }
        //public override Base[] CheckNearBy(PointD Plocation)
        //{
        //    List<Base> objs = new List<Base>(base.CheckNearBy(Plocation));
        //    objs.AddRange(Center.CheckNearBy(Plocation));
        //    return objs.ToArray();
        //}
        public override void ComponentBuilding(Base component)
        {
            if (CenterPoint == null || Lines[0] != null && Lines[0].Point1 != null) return;
            tempLocation[0] = SpareCoordinate_;
            PointD tmp = Pad.PxyToXY(SpareCoordinate);
            r = CenterPoint.ToPointD().DistanceTo(tmp);
            bxj = Math.Sin(nj / 2) * r;
            //C = 0;
            for (int i = 1; i < Lines.Count; i++)
            {
                tmp = tmp.RotateAt(CenterPoint.ToPointD(), zxj);
                tempLocation[i] = Pad.XYToPxy(tmp);
                //Lines[i].SpareCoordinate_ = tmp;
                //Lines[i].ComponentChanged(Lines[i].Point1);
                //C += Lines[i].Length;
            }
            //Lines[Lines.Count - 1].SpareCoordinate_=
            //Lines[Lines.Count - 1].ComponentChanged(Lines[Lines.Count - 1].Point1);
            //C += Lines[Lines.Count - 1].Length;
            Circumference = Math.Cos(nj / 2) * r * 2 * Lines.Count;
            Area = Lines.Count * r * r * Math.Sin(zxj) / 2;
            ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}{Resources.LeftParenthesis}{Resources.Translate("Center")}{Resources.ColonSeparate}{CenterPoint}{Resources.CommaSeparate}{Resources.Translate("Radius")} = {r}");
            base.ComponentBuilding(component);
        }
        public override void ComponentChanged(ShapeBase component)
        {
            r = CenterPoint.NewXY.DistanceTo(Lines[0].Point1.NewXY);
            bxj = Math.Sin(nj / 2) * r;
            base.ComponentChanged(component);
        }
        //public override void Paint(Graphics gra)
        //{
        //    base.Paint(gra);
        //    Center?.Paint(gra);
        //}
        public override void ChangePoint(PointBase oldPoint, PointBase newPoint)
        {
            if (ReferenceEquals(CenterPoint, oldPoint))
            {
                CenterPoint = newPoint;
            }
            else
            {
                base.ChangePoint(oldPoint, newPoint);
            }
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            gra.FillPolygon(Core.Helper.Painter.VirtualBrush, Utility.ToPointFs(tempLocation));
            for (int i = 0; i < tempLocation.Length; i++)
            {
                int iNext = i == tempLocation.Length - 1 ? 0 : i + 1;
                gra.DrawLineSegment(tempLocation[i], tempLocation[iNext]);
                gra.DrawPoint(tempLocation[i]);
            }
        }
        public override bool LocationUsed(IList<PointD> locations)
        {
            return Center.AlmostEquals(locations[0], false) && InPoints[0].ToPointD().AlmostEquals(locations[1], false);
        }
        public override object GetCopyInfo()
        {
            PointCreatingArgs[] res = new PointCreatingArgs[2] { new PointCreatingArgs(Center, false, CenterPoint.ToolType == ToolTypeName.zbd), new PointCreatingArgs(InPoints[0].ToPointD(), false, InPoints[0].ToolType == ToolTypeName.zbd) };
            return res;
        }
        public override object CopyAndPaste(SketchPad pad)
        {
            RegularPolygon rp = new RegularPolygon(pad, Utility.GetNextAvailableName(Name, pad.CheckObjectNameExist), LinesCount, LayerItem != null);
            afterNewCopy(rp);
            return rp;
        }
        public override void CreateComponents()
        {
            if (CenterPoint == null)
            {
                CenterPoint = Pad.CreatePoint(Resources.Translate("Center"), SpareCoordinate_);
                BaryCenter = CenterPoint.ToPointD();
                Pad.TrackObj = this;
            }
            else
            {
                TwoPointsLineSegment line = null;
                for (int i = 0; i < Lines.Count; i++)
                {
                    line = new TwoPointsLineSegment(Pad, $"{Resources.Translate("Edge")}{i + 1}", false) { AllowFix = false };
                    SetLine(i, line);
                    line.CreateComponents(Pad.CreatePoint($"{Resources.Translate("Edge")}{i + 1}{Resources.Join}{Resources.Translate("EndPoint")}1/{Resources.Translate("Edge")}{(i == 0 ? Lines.Count : i)}{Resources.Join}{Resources.Translate("EndPoint")}2", tempLocation[i], i == 0, new PointCollectionBase[] { new Universal(CenterPoint.ToPointD()) }));
                    if (i > 0)
                    {
                        Lines[i - 1].CreateComponents(line.Point1, true);
                    }
                }
                line.CreateComponents(Lines[0].Point1, true);
                tempLocation = null;
                base.CreateComponents();
            }
        }
    }
}
